{
  // ParseQueryString

  function parseQueryString(queryStr: string) {
    if (!queryStr || !queryStr.length) {
      return {};
    }

    const queryObj: {
      [props: string]: any;
    } = {};

    const items = queryStr.split('&');

    items.forEach((item: string) => {
      const [key, value] = item.split('=');
      if (queryObj[key]) {
        if (Array.isArray(queryObj[key])) {
          queryObj[key].push(value);
        } else {
          queryObj[key] = [queryObj[key], value];
        }
      } else {
        queryObj[key] = value;
      }
    });
    return queryObj;
  }

  // console.log(parseQueryString('a=1&a=2&a=0&b=2&c=3'));
}

{
  type ParseParam<StrParam extends string> = StrParam extends `${infer Key}=${infer Value}`
    ? {
        [K in Key]: Value;
      }
    : Record<string, any>;

  // prettier-ignore
  type MergeParams<OneParam extends Record<string, any>, OtherParam extends Record<string, any>> = {
    [Key in keyof OneParam | keyof OtherParam]: 
      Key extends keyof OneParam
        ? Key extends keyof OtherParam
          ? MergeValues<OneParam[Key], OtherParam[Key]>
          : OneParam[Key]
        : Key extends keyof OtherParam
          ? OtherParam[Key]
          : never;
  };

  // prettier-ignore
  type MergeValues<One, Other> = One extends Other
    ? One
    : Other extends unknown[]
      ? [One, ...Other]
      : [One, Other];

  // prettier-ignore
  type ParseQueryString<Str extends string> = 
    Str extends `${infer Param}&${infer Rest}`
      ? MergeParams<ParseParam<Param>, ParseQueryString<Rest>>
      : ParseParam<Str>;

  function parseQueryString<Str extends string>(queryStr: Str): ParseQueryString<Str> {
    if (!queryStr || !queryStr.length) {
      return {} as any;
    }

    const queryObj = {} as any;

    const items = queryStr.split('&');

    items.forEach((item: string) => {
      const [key, value] = item.split('=');
      if (queryObj[key]) {
        if (Array.isArray(queryObj[key])) {
          queryObj[key].push(value);
        } else {
          queryObj[key] = [queryObj[key], value];
        }
      } else {
        queryObj[key] = value;
      }
    });
    return queryObj;
  }

  parseQueryString('a=1&a=2&a=0&b=2&c=3').a;
}
